#include "zoomablelabel.h"
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QDebug>
#include <QMenu>
#include <QAction>
#include <QContextMenuEvent>
#include <QTimer>

ZoomableLabel::ZoomableLabel(QWidget *parent)
    : QLabel(parent), scaleFactor(1.0), maxScaleFactorValue(8.0), // 默认最大放大10倍
    offset(0, 0), dragging(false), cacheDirty(true),
    drawingROI(false), currentROI(QRect())
{
    setAlignment(Qt::AlignCenter);
    setScaledContents(false);

    contextMenu = new QMenu(this);
    QAction *resetAction = contextMenu->addAction("复原");
    QAction *clearROIAction = contextMenu->addAction("清除ROI");
    connect(resetAction, &QAction::triggered, this, &ZoomableLabel::resetZoom);
    connect(clearROIAction, &QAction::triggered, this, &ZoomableLabel::clearROI);
}

void ZoomableLabel::setMaxScaleFactor(float maxFactor)
{
    if (maxFactor > 1.0f) {
        maxScaleFactorValue = maxFactor;
    }
}

float ZoomableLabel::maxScaleFactor() const
{
    return maxScaleFactorValue;
}

void ZoomableLabel::setPixmap(const QPixmap &pixmap)
{
    originalPixmap = pixmap;
    scaleFactor = 1.0;
    offset = QPoint(0, 0);
    clearROI();
    cacheDirty = true;
    updateScaledPixmap();
}

void ZoomableLabel::setOriginalPixmap(const QPixmap &pixmap)
{
    originalPixmap = pixmap;
    scaleFactor = 1.0;
    offset = QPoint(0, 0);
    clearROI();
    cacheDirty = true;
    updateScaledPixmap();
}

void ZoomableLabel::updateScaledPixmap()
{
    if (!originalPixmap.isNull()) {
        QSize labelSize = size();
        QSize imageSize = originalPixmap.size();

        float widthScaleFactor = static_cast<float>(labelSize.width()) / imageSize.width();
        float heightScaleFactor = static_cast<float>(labelSize.height()) / imageSize.height();

        scaleFactor = qMin(widthScaleFactor, heightScaleFactor);

        cacheDirty = true;
        update();
    }
}

void ZoomableLabel::resetZoom()
{
    scaleFactor = 1.0;
    offset = QPoint(0, 0);
    cacheDirty = true;
    updateScaledPixmap();
    update();
}

QPoint ZoomableLabel::windowToImage(const QPoint& windowPoint)
{
    if (originalPixmap.isNull()) {
        return QPoint();
    }

    QSize scaledSize = cachedPixmap.size();
    QPoint drawPoint = rect().center() - QPoint(scaledSize.width() / 2, scaledSize.height() / 2) + offset;

    QPoint imagePoint = windowPoint - drawPoint;

    imagePoint = QPoint(
        static_cast<int>(imagePoint.x() / scaleFactor),
        static_cast<int>(imagePoint.y() / scaleFactor)
        );

    QSize imageSize = originalPixmap.size();
    imagePoint.setX(qBound(0, imagePoint.x(), imageSize.width()));
    imagePoint.setY(qBound(0, imagePoint.y(), imageSize.height()));

    return imagePoint;
}

void ZoomableLabel::startROIDrawing()
{
    drawingROI = true;
    currentROI = QRect();
    setCursor(Qt::CrossCursor);
    update();
}

void ZoomableLabel::stopROIDrawing()
{
    drawingROI = false;
    setCursor(Qt::ArrowCursor);
    update();
}

void ZoomableLabel::clearROI()
{
    currentROI = QRect();
    emit roiCleared();
    update();
}

bool ZoomableLabel::hasROI() const
{
    return !currentROI.isNull() && currentROI.isValid();
}

QRect ZoomableLabel::getROI() const
{
    return currentROI;
}

void ZoomableLabel::wheelEvent(QWheelEvent *event)
{
    QPoint numDegrees = event->angleDelta();
    if (!numDegrees.isNull() && !originalPixmap.isNull()) {
        float oldScale = scaleFactor;

        // 计算新的缩放因子，但不超过最大限制
        float newScale = scaleFactor;
        if (numDegrees.y() > 0) {
            newScale *= 1.1f;
            // 检查是否超过最大缩放限制
            if (newScale > maxScaleFactorValue) {
                newScale = maxScaleFactorValue;
                // 达到最大缩放时给出视觉反馈（可选）
                setCursor(Qt::ForbiddenCursor);
                QTimer::singleShot(500, this, [this]() { setCursor(Qt::ArrowCursor); });
            }
        } else {
            newScale /= 1.1f;
            // 重置光标状态
            if (cursor().shape() == Qt::ForbiddenCursor) {
                setCursor(Qt::ArrowCursor);
            }
        }

        // 应用缩放因子（如果变化超过阈值）
        if (qAbs(newScale - scaleFactor) > 0.01f) {
            scaleFactor = newScale;

            // 计算鼠标位置相对于图像中心的偏移（考虑当前偏移量）
            QPointF mousePos = event->position();
            QSize scaledSize = originalPixmap.size() * oldScale;
            QPointF drawPoint = QPointF(rect().center()) - QPointF(scaledSize.width()/2.0, scaledSize.height()/2.0) + offset;
            QPointF imagePos = (mousePos - drawPoint) / oldScale;

            // 计算新的偏移量，使鼠标下的图像位置保持不变
            QSize newScaledSize = originalPixmap.size() * scaleFactor;
            QPointF newDrawPoint = QPointF(rect().center()) - QPointF(newScaledSize.width()/2.0, newScaledSize.height()/2.0);
            offset = (mousePos - newDrawPoint - imagePos * scaleFactor).toPoint();

            cacheDirty = true;
            update();
        }
    }
}

void ZoomableLabel::resizeEvent(QResizeEvent *event)
{
    QLabel::resizeEvent(event);
    updateScaledPixmap();
}

void ZoomableLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    resetZoom();
}

void ZoomableLabel::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        if (drawingROI) {
            roiStartPoint = event->pos();
            roiEndPoint = event->pos();
        } else {
            dragging = true;
            lastMousePos = event->pos();
        }
    }
}

void ZoomableLabel::mouseMoveEvent(QMouseEvent *event)
{
    if (dragging) {
        QPoint delta = event->pos() - lastMousePos;
        offset += delta;
        lastMousePos = event->pos();
        update();
    } else if (drawingROI) {
        roiEndPoint = event->pos();
        update();
    }
}

void ZoomableLabel::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        if (dragging) {
            dragging = false;
        } else if (drawingROI) {
            QRect windowRect = QRect(roiStartPoint, roiEndPoint).normalized();

            QPoint topLeft = windowToImage(windowRect.topLeft());
            QPoint bottomRight = windowToImage(windowRect.bottomRight());

            currentROI = QRect(topLeft, bottomRight);

            emit roiDrawn(currentROI);
        }
    }
}

void ZoomableLabel::contextMenuEvent(QContextMenuEvent *event)
{
    contextMenu->exec(event->globalPos());
}

void ZoomableLabel::paintEvent(QPaintEvent *event)
{
    if (originalPixmap.isNull()) {
        QLabel::paintEvent(event);
        return;
    }

    QPainter painter(this);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);

    // 仅在需要时更新缓存
    if (cacheDirty) {
        QSize scaledSize = originalPixmap.size() * scaleFactor;

        // 使用快速缩放模式当缩放因子较大时
        Qt::TransformationMode mode = (scaleFactor > 2.0f) ?
                                          Qt::FastTransformation :
                                          Qt::SmoothTransformation;

        cachedPixmap = originalPixmap.scaled(
            scaledSize,
            Qt::KeepAspectRatio,
            mode
            );
        cacheDirty = false;
    }

    QSize pixSize = cachedPixmap.size();
    QRect widgetRect = rect();
    int drawX = widgetRect.center().x() - pixSize.width()/2 + offset.x();
    int drawY = widgetRect.center().y() - pixSize.height()/2 + offset.y();

    painter.drawPixmap(drawX, drawY, cachedPixmap);

    if (drawingROI) {
        QRect roiRect = QRect(roiStartPoint, roiEndPoint).normalized();
        painter.setPen(QPen(Qt::red, 2, Qt::DashLine));
        painter.setBrush(Qt::NoBrush);
        painter.drawRect(roiRect);
    }
    else if (hasROI()) {
        int roiX = drawX + currentROI.x() * scaleFactor;
        int roiY = drawY + currentROI.y() * scaleFactor;
        int roiW = currentROI.width() * scaleFactor;
        int roiH = currentROI.height() * scaleFactor;
        QRect windowRect(roiX, roiY, roiW, roiH);

        painter.setPen(QPen(Qt::green, 2));
        painter.setBrush(Qt::NoBrush);
        painter.drawRect(windowRect);
    }
}
